package pushup.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;

import org.eclipse.core.runtime.IProgressMonitor;

public class Register extends AbstractTypeRelatedEntity {

	private HashMap<String, Package> packages = new HashMap<String, Package>();
	private HashMap<String, Type> types = new HashMap<String, Type>();
	
	private Statistics statistics = new Statistics();
	
	public Package getPackage(String name){
		if (!packages.containsKey(name)){
			packages.put(name, new Package(name));
		}
		
		return packages.get(name);
	}
	
	public Type getType(String packagename, String name, String shortName){
		Package pack = getPackage(packagename);
		
		if (!types.containsKey(name)){
			Type stub = new Type(name, shortName);
			stub.setStub(true);
			types.put(name, stub);
		}
		
		Type type = types.get(name);
		
		pack.addType(type);
		type.setPackage(pack);
				
		return type;
	}

	public Type getCurrentType() {
		return relatedType;
	}

	public void setCurrentType(Type currentType) {
		this.relatedType = currentType;
	}
	
	public String toString(){
		StringBuilder b = new StringBuilder();
		b.append("\n");
		for(Type type: types.values()){
			b.append(type.toString());
		}
		b.append("\n");
		return b.toString();
	}
	
	public void computeSimilarities(IProgressMonitor monitor){
		for(Package p : packages.values()){
			
			if(p.isPrimitiveStub()){
				continue;
			}
			
			// for each package, I check internal similarities
			monitor.setTaskName("Computing similarities for package: " + p.getName());
			for(Type typeA: p.getTypes()){
				for(Type typeB: p.getTypes()){
					if(!typeA.equals(typeB) && !typeA.hasAlreadyBeenMatchedWith(typeB)){
						typeA.computeSimilarity(typeB);
					}
				}
				monitor.worked(1);
			}
			
			for(Type type: p.getTypes()){
				type.freeMatchedAttempts();
				statistics.handleSimilarity(type.getMaxSimilarities());
			}
		}
		
	}
	
	public Collection<Type> getTypes(){
		return types.values();
	}

	public Statistics getStatistics() {
		return statistics;
	}

	public void reset() {
		types.clear();
		statistics.reset();
	}

	public ArrayList<Type> getTypesWithSimilarities() {
		ArrayList<Type> similarTypes = new ArrayList<Type>();
		
		for(Type type : getTypes()){
			if(type.hasSimilarities()){
				similarTypes.add(type);
			}
		}
		
		Collections.sort(similarTypes, new TypeComparator());
		
		return similarTypes;
	}

	
}
